﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Core.ActionResults
{
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.IO;
	using System.Text;
	using System.Web.Mvc;
	using System.Xml;
	using Falcon.Core.Domain;
	using Falcon.Core.Domain.Enums;
	using Falcon.Core.Extensions;

	public class UserMessageDownloadResult : ActionResult
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="UserMessageDownloadResult"/> class.
		/// </summary>
		public UserMessageDownloadResult()
		{
			
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="UserMessageDownloadResult"/> class.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <param name="messages">The messages.</param>
		/// <param name="action">The action.</param>
		public UserMessageDownloadResult(int id, IList<UserMessage> messages, UserMessageAction action) 
			: this()
		{
			this.UserId = id;
			this.Messages = messages;
			this.Action = action;
		}

		/// <summary>
		/// Gets or sets the user id.
		/// </summary>
		/// <value>The user id.</value>
		public int UserId
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the messages.
		/// </summary>
		/// <value>The messages.</value>
		public IList<UserMessage> Messages
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the action.
		/// </summary>
		/// <value>The action.</value>
		public UserMessageAction Action
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the name of the file.
		/// </summary>
		/// <value>The name of the file.</value>
		public string FileName
		{
			get
			{
				return string.Format(
					CultureInfo.InvariantCulture, 
					"messages-{0}.{1}", 
					DateTime.Now.ToString("M-d-yyyy-h:mm-tt", CultureInfo.InvariantCulture), 
					this.FileExtension);
			}
		}

		/// <summary>
		/// Gets the file extension.
		/// </summary>
		/// <value>The file extension.</value>
		public string FileExtension
		{
			get
			{
				if (this.Action == UserMessageAction.ExportXml)
				{
					return "xml";
				}

				return this.Action == UserMessageAction.ExportCsv ? "csv" : "txt";
			}
		}

		/// <summary>
		/// Enables processing of the result of an action method by a custom type that inherits from <see cref="T:System.Web.Mvc.ActionResult"/>.
		/// </summary>
		/// <param name="context">The context within which the result is executed.</param>
		public override void ExecuteResult(ControllerContext context)
		{
			if (context == null)
			{
				throw new ArgumentNullException("context");
			}

			using (var stream = new MemoryStream())
			{
				var content = this.GetContent(stream);

				context.HttpContext.Response.Clear();
				context.HttpContext.Response.AppendHeader("content-disposition", string.Format(CultureInfo.InvariantCulture, "attachment; filename={0}", this.FileName));
				context.HttpContext.Response.AppendHeader("Content-Length", content.Length.ToString(CultureInfo.InvariantCulture));
				context.HttpContext.Response.ContentType = "application/octet-stream";
				context.HttpContext.Response.BinaryWrite(content);

				stream.Dispose();
			}
		}

		/// <summary>
		/// Gets the content.
		/// </summary>
		/// <param name="stream">The stream.</param>
		/// <returns></returns>
		public byte[] GetContent(MemoryStream stream)
		{
			if (this.Action == UserMessageAction.ExportXml)
			{
				return this.GetXml(stream);
			}

			return this.Action == UserMessageAction.ExportCsv ? this.GetCsv(stream) : this.GetText(stream);
		}

		/// <summary>
		/// Gets the XML.
		/// </summary>
		/// <param name="stream">The stream.</param>
		/// <returns></returns>
		public byte[] GetXml(MemoryStream stream)
		{
			using (var writer = new XmlTextWriter(stream, Encoding.UTF8))
			{
				writer.Formatting = Formatting.Indented;

				writer.WriteStartDocument();

				writer.WriteStartElement("messages");

				foreach (var message in this.Messages)
				{
					writer.WriteStartElement("message");
					writer.WriteElementString("date", message.Created.ToString(CultureInfo.InvariantCulture));

					if (message.Folder != null && 
						message.Folder.Id > 0)
					{
						writer.WriteElementString("folder", message.Folder.Title);
					}
					else
					{
						if (message.Receiver.Id == this.UserId)
						{
							writer.WriteElementString("folder", UserMessageFolder.Inbox);
						}
						else
						{
							writer.WriteElementString("folder", UserMessageFolder.Sent);
						}
					}

					writer.WriteElementString("receiver", message.Receiver.Name);
					writer.WriteElementString("sender", message.Sender.Name);
					writer.WriteElementString("title", message.Title);
					writer.WriteElementString("body", message.Body);

					writer.WriteEndElement();
				}

				writer.WriteEndElement();

				writer.Flush();

				return stream.ToArray();
			}
		}

		/// <summary>
		/// Gets the CSV.
		/// </summary>
		/// <param name="stream">The stream.</param>
		/// <returns></returns>
		public byte[] GetCsv(MemoryStream stream)
		{
			using (var writer = new StreamWriter(stream))
			{
				writer.Write("ID,Date,Folder,Receiver,Sender,Title,Body");

				writer.WriteLine();

				foreach (var message in this.Messages)
				{
					writer.Write(message.Id);
					writer.Write(",");
					writer.Write(message.Created.ToString(CultureInfo.InvariantCulture));
					writer.Write(",");

					if (message.Folder != null && 
						message.Folder.Id > 0)
					{
						writer.Write(message.Folder.Title);
					}
					else
					{
						if (message.Receiver.Id == this.UserId)
						{
							writer.Write(UserMessageFolder.Inbox);
						}
						else
						{
							writer.Write(UserMessageFolder.Sent);
						}
					}

					writer.Write(",");
					writer.Write(message.Receiver.Name);
					writer.Write(",");
					writer.Write(message.Sender.Name);
					writer.Write(",");
					writer.Write(message.Title);
					writer.Write(",");
					writer.Write(message.Body);

					writer.WriteLine();
				}

				writer.Flush();

				return stream.ToArray();
			}
		}

		/// <summary>
		/// Gets the text.
		/// </summary>
		/// <param name="stream">The stream.</param>
		/// <returns></returns>
		public byte[] GetText(MemoryStream stream)
		{
			using (var writer = new StreamWriter(stream))
			{
				foreach (var message in this.Messages)
				{
					writer.Write(string.Concat("ID: ", message.Id));
					writer.WriteLine();
					writer.Write(string.Concat("Date: ", message.Created.ToString(CultureInfo.InvariantCulture)));
					writer.WriteLine();

					if (message.Folder != null && 
						message.Folder.Id > 0)
					{
						writer.Write(string.Concat("Folder: ", message.Folder.Title));
					}
					else
					{
						if (message.Receiver.Id == this.UserId)
						{
							writer.Write(string.Concat("Folder: ", UserMessageFolder.Inbox));
						}
						else
						{
							writer.Write(string.Concat("Folder: ", UserMessageFolder.Sent));
						}
					}

					writer.WriteLine();
					writer.Write(string.Concat("Receiver: ", message.Receiver.Name));
					writer.WriteLine();
					writer.Write(string.Concat("Sender: ", message.Sender.Name));
					writer.WriteLine();
					writer.Write(string.Concat("Title: ", message.Title));

					writer.WriteLine();
					writer.WriteLine();

					writer.Write("Message:");

					writer.WriteLine();
					writer.WriteLine();

					writer.Write(message.Body);

					writer.WriteLine();
					writer.Write("================================================================================");
					writer.WriteLine();
				}

				writer.Flush();

				return stream.ToArray();
			}
		}
	}
}